/*
 * =====================================================================================
 *
 *       Filename:  dlist.c
 *
 *    Description:  
 *
 *        Version:  1.0
 *        Created:  07/04/2011 11:38:13 PM
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  YOUR NAME (), 
 *        Company:  
 *
 * =====================================================================================
 */

#include "dlist.h"

typedef struct _DListNode
{
    struct _DListNode* prev;
    struct _DListNode* next;
    void *data;
}DListNode;

struct _DList
{
    DListNode *first;
}DList;

static DListNode* dlist_node_create(void **ppData)
{
    DListNode* node = malloc(sizeof(DListNode));
    if (node != NULL)
    {
        node->prev = NULL;
        node->next = NULL;
        node->data = *ppData;
    }

    return node;
}

static DListNode* dlist_get_node(DList *pDlist, int index, int last_flag)
{
    assert(NULL != pDlist);

    int i = index;
    DListNode *cursor = pDlist->first;  
    
    if (last_flag)
    {
        while(cursor->next != NULL)
        {
            cursor = cursor->next;
        }

        return cursor;
    }

    while ((--i != 0) && (cursor != NULL))
    {
        cursor = cursor->next;
    }

    return cursor;
}

static void dlist_node_destroy(DListNode* node)
{
    if (node != NULL)
    {
        node->next = NULL;
        node->prev = NULL;
        node->data = NULL;
        free(node);
    }
    
    return ;
}

DListRet dlist_create(DList *pDList)
{
    assert(NULL != pDList);

    pDList = (DList *)malloc(sizeof(DList));
    if (NULL == pDList)
    {
        fprintf(stderr, "list malloc error %s\n", strerror(errno));
        return DLIST_RET_FAIL;
    }

    pDList->first = NULL;

    return DLIST_RET_OK;
}

//insert dlist last
DListRet dlist_insert(DList *thiz, size_t index, void *data)
{
    assert(NULL != thiz);
    assert(NULL != data);

    DListNode *pNode;
    DListNode *cursor;

    pNode = dlist_node_create(&data);
    if (NULL == pNode)
    {
        return DLIST_RET_OOM;
    }

    if (thiz->first == NULL)
    {
        thiz->first = pNode;
        return DLIST_RET_OK;
    }

    cursor = dlist_get_node(thiz, 0, 1);

    cursor->next = pNode;
    pNode->prev = cursor;

    return DLIST_RET_OK;
}

//
DListRet dlist_get_by_index(DList *thiz, size_t index, void **ppData)
{
    assert(NULL != thiz);
    assert(NULL != *ppData);

    DListNode* cursor;
    
    cursor = dlist_get_node(thiz, index, 0);
    if (cursor != NULL)
    {
        *ppData = cursor;
    }

    return cursor != NULL ? DLIST_RET_OK : DLIST_RET_PARAMS;
}

DListRet dlist_append(DList* thiz, void* data)
{
    assert(NULL != thiz); 
    assert(NULL != data);

    DListNode* cursor = dlist_get_node(thiz, 0, 1);

    DListNode* new = dlist_node_create(&data);
    if (NULL != new)
    {
        new->next = NULL; 
        new->next->prev = cursor;
        cursor->next = new;
    }

    return new != NULL?DLIST_RET_OK : DLIST_RET_OOM;
}

DListRet dlist_delete(DList* thiz, size_t index)
{
    assert(NULL != thiz);

    DListNode* cursor = dlist_get_node(thiz, index, 0);
    if (cursor == NULL)
    {
        return DLIST_RET_PARAMS;
    }

    if (NULL !=cursor)
    {
        if (cursor == thiz->first)
        {
            thiz->first = cursor->next;
        }

        if (cursor->next != NULL)
        {
            cursor->next->prev = cursor->prev;
        }

        if (cursor->prev != NULL)
        {
            cursor->prev->next = cursor->next;
        }

        dlist_node_destroy(cursor);
    }

    return DLIST_RET_OK;
}

//
DListRet dlist_set_by_index(DList *thiz, size_t index, void *data)
{
    assert(NULL != thiz);
    assert(NULL != data);

    DListNode* cursor;
    cursor = dlist_get_node(thiz, index, 0);
    if (NULL != cursor)
    {
        free(cursor);
        cursor = data;
    }

    return cursor != NULL ? DLIST_RET_OK : DLIST_RET_FAIL;
}

size_t dilist_length(DList *thiz)
{
    int num;

    DListNode* iter = thiz->first;
    while (iter != NULL)
    {
        num++;
        iter = iter->next;
    }
    
    return num;
}

DListRet dlist_print(DList *thiz, DListDataPrintFunc print)
{
    assert(NULL != thiz);
    assert(NULL != print);

    DListNode* iter = thiz->first;

    while (iter != NULL)
    {
        print(iter);
        iter = iter->next;
    }

    return DLIST_RET_OK;
}

void dlist_destroy(DList *thiz)
{
    assert(thiz != NULL);

    DListNode *cursor = thiz->first;
    DListNode *next ;

    while(cursor)
    {
        next = cursor->next;
        dlist_node_destroy(cursor);
        cursor = next;
    }
}

int main(void)
{
    return 0;

}

